# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# (C) 2012 Remek Zajac
#!/usr/bin/python

import os
from lxml import etree

class ColourStyle(object):
    def __init__(self, colourTupleMax, colourTupleMin=None):
        self.m_colourTupleMax = colourTupleMax
        if colourTupleMin:
            self.m_colourTupleMin = colourTupleMin
        else:
            self.m_colourTupleMin = colourTupleMax

    def colour(self, percentModifier = 100):
        red   = self.m_colourTupleMax[0]*percentModifier+self.m_colourTupleMin[0]*(1-percentModifier)
        green = self.m_colourTupleMax[1]*percentModifier+self.m_colourTupleMin[1]*(1-percentModifier)
        blue  = self.m_colourTupleMax[2]*percentModifier+self.m_colourTupleMin[2]*(1-percentModifier)
        alpha = self.m_colourTupleMax[3]*percentModifier+self.m_colourTupleMin[3]*(1-percentModifier)
        return (red, green, blue, alpha)

class LineStyle:
    def __init__(self, colour, width, continuity):
        self.colour = colour
        self.m_width = width
        self.m_continuity = continuity

    def width(self):
        return self.m_width

    def colour(self):
        return self.colour


class ColoursConfigParser:
    def __init__(self, parent):
        self.m_colours = {}
        self.parent = parent
        
    def do(self, elem):
        if elem.tag == 'colour':
            name = elem.get("name")
            aliasFor = elem.get("aliasFor")
            if aliasFor:
                assert(self.m_colours.has_key(aliasFor))
                self.m_colours[name] = self.m_colours[aliasFor]
            else:
                red = float(elem.get("red"))
                green = float(elem.get("green"))
                blue = float(elem.get("blue"))
                if red > 1 or green > 1 or blue > 1:
                    red /= 255
                    green /= 255
                    blue /= 255
                alpha = float(elem.get("alpha"))
                assert(not self.m_colours.has_key(name))
                self.m_colours[name] = ColourStyle((red, green, blue, alpha))
            print self.parent.indentationStr()+"Added colour:"+name
        else:
            print self.parent.indentationStr()+"Unknown tag:"+elem.tag

    def colour(self, name):
        return self.m_colours[name]

                       

class WaysConfigParser:
    def __init__(self, parent):
        self.m_ways = {}
        self.currentHighwayName = None
        self.parent = parent
        
    def do(self, elem):
        if elem.tag == 'highway':
            self.currentHighwayName = elem.get("name")
            print self.parent.indentationStr()+"Parsing way:"+self.currentHighwayName
        elif elem.tag == 'style':
            zoom = int(elem.get("zoom"))
            colour = elem.get("colour")
            width = int(elem.get("width"))
            continuity = elem.get("continuity")
            assert(not self.m_ways.has_key((self.currentHighwayName, zoom)))
            assert(self.parent.colours.colour(colour))
            self.m_ways[(self.currentHighwayName,zoom)] = LineStyle(self.parent.colours.colour(colour), width, continuity)
            print self.parent.indentationStr()+"Config parser added way style for zoom"+str(zoom)
        else:
            print self.parent.indentationStr()+"Unknown tag:"+elem.tag

    def way(self, name, zoom):
        #here we return the smallest zoom larger or greter than supplied
        for z in reversed(range(1,zoom+1)):
            if self.m_ways.has_key((name, z)):
                return self.m_ways[(name,z)]
        return None


class ScriptsConfigParser:
    def __init__(self, parent):
        self.parent = parent
        
    def do(self, elem):
        if elem.tag == 'output':
            self.outputfolder = elem.get("folder")
            self.unique = bool(elem.get("unique"))
            print self.parent.indentationStr()+"Script output destination folder:"+self.outputfolder
        else:
            print self.parent.indentationStr()+"Unknown tag:"+elem.tag            
    
class Config:
    def __init__(self):
        self.configFile = 'config.xml'
        self.currentSpecialisedParser = None
        self.colours = ColoursConfigParser(self)
        self.scripts = ScriptsConfigParser(self)
        self.ways = WaysConfigParser(self)
        self.level = 0
        self.m_lastUpdated = os.path.getmtime(self.configFile)

    def colours(self):
        return self.colours

    def ways(self):
        return self.ways

    def scripts(self):
        return self.scripts

    def indentationStr(self):
        str = ('')
        for _ in range(self.level):
            str += '  '
        return str
    
    def parse(self):
        parsingContext = etree.iterparse( self.configFile, events=("start", "end") )
        try:
            for event, elem in parsingContext :
                if event == "start":
                    print self.indentationStr()+'<'+elem.tag+'>'
                    self.level+=1
                else:
                    self.level-=1                    
                    print self.indentationStr()+'<'+elem.tag+'>'              
                if elem.tag == 'colours':
                    if event == "start":
                        self.currentSpecialisedParser = self.colours
                    else:
                        self.currentSpecialisedParser = None
                elif elem.tag == 'ways':
                    if event == "start":
                        self.currentSpecialisedParser = self.ways
                    else:
                        self.currentSpecialisedParser = None
                elif elem.tag == 'scripts':
                    if event == "start":
                        self.currentSpecialisedParser = self.scripts
                    else:
                        self.currentSpecialisedParser = None                          
                elif self.currentSpecialisedParser:
                    if event == "start":
                        self.currentSpecialisedParser.do(elem)            
        except etree.XMLSyntaxError:
            assert(False)#failed to parse config file, this is fatal
        del parsingContext

    def lastUpdated(self):
        return self.m_lastUpdated
